import OlMap from 'ol/Map';
import Draw, { DrawEvent } from 'ol/interaction/Draw';
import Modify, { ModifyEvent } from 'ol/interaction/Modify';
import Snap from 'ol/interaction/Snap';
import Select, { SelectEvent } from 'ol/interaction/Select';
import DragPan from 'ol/interaction/DragPan';
import { Collection, Feature } from 'ol';
import Geometry from 'ol/geom/Geometry';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import { GeoJSON } from 'ol/format';
import { Style, Circle, Fill, Stroke, Text } from 'ol/style';
import { Circle as CircleGeometry, Point, Polygon } from 'ol/geom';

/**
 * 绘制类型枚举
 */
export enum DrawType {
  POINT = 'Point',
  LINE_STRING = 'LineString',
  POLYGON = 'Polygon',
  CIRCLE = 'Circle',
  RECTANGLE = 'Circle' // OpenLayers中矩形通过Circle实现
}

/**
 * 编辑器配置选项
 */
export interface EditorOptions {
  map: OlMap;
  source?: VectorSource;
  style?: Style | Style[] | ((feature: Feature) => Style | Style[]);
  snapping?: boolean; // 是否启用吸附功能
  snappingDistance?: number; // 吸附距离
}

/**
 * 编辑历史记录项
 */
interface HistoryItem {
  type: 'add' | 'modify' | 'delete';
  feature: Feature;
  geometry?: any;
}

/**
 * 交互式编辑器类，提供矢量要素的绘制、编辑、删除等功能
 */
export class Editor {
  private map: OlMap;
  private source: VectorSource<any>;
  private layer: VectorLayer<any>;
  private drawInteraction: Draw | null = null;
  private modifyInteraction: Modify | null = null;
  private selectInteraction: Select | null = null;
  private snapInteraction: Snap | null = null;
  private drawType: DrawType | null = null;
  private history: HistoryItem[] = [];
  private historyIndex: number = -1;
  private listeners: Map<string, Function[]> = new Map();
  private defaultStyle: Style;
  private snapping: boolean;
  private snappingDistance: number;

  /**
   * 构造函数
   * @param options 编辑器配置选项
   */
  constructor(options: EditorOptions) {
    this.map = options.map;
    this.snapping = options.snapping !== undefined ? options.snapping : true;
    this.snappingDistance = options.snappingDistance || 10;
    
    // 创建默认样式
    this.defaultStyle = new Style({
      fill: new Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
      stroke: new Stroke({ color: '#ffcc33', width: 2 }),
      image: new Circle({ radius: 5, fill: new Fill({ color: '#ffcc33' }) })
    });
    
    // 初始化数据源和图层
    if (options.source) {
      this.source = options.source;
      // 查找是否已有对应的图层
      const layers = this.map.getLayers().getArray();
      const existingLayer = layers.find(layer => {
        return layer instanceof VectorLayer && layer.getSource() === this.source;
      });
      this.layer = existingLayer as VectorLayer<any> || new VectorLayer<any>({
        source: this.source,
        style: options.style as any || this.defaultStyle
      });
      if (!existingLayer) {
        this.map.addLayer(this.layer);
      }
    } else {
      this.source = new VectorSource();
      this.layer = new VectorLayer({
        source: this.source,
        style: options.style as any || this.defaultStyle
      });
      this.map.addLayer(this.layer);
    }
    
    // 初始化选择交互
    this.initSelectInteraction();
    
    console.log('Editor initialized');
  }

  /**
   * 初始化选择交互
   */
  private initSelectInteraction(): void {
    this.selectInteraction = new Select({
      layers: [this.layer],
      style: (feature: any) => {
        // StyleFunction需要两个参数：feature和resolution
        const originalStyle = this.layer.getStyleFunction()?.(feature, 1) || this.defaultStyle;
        // 为选中要素添加高亮样式
        if (Array.isArray(originalStyle)) {
          return originalStyle.map(style => {
            // clone方法不需要参数
            const clone = style.clone();
            const stroke = clone.getStroke()?.clone() || new Stroke();
            stroke.setColor('#ff0000');
            stroke.setWidth(3);
            clone.setStroke(stroke);
            return clone;
          });
        } else if (originalStyle) {
          const clone = originalStyle.clone();
          const stroke = clone.getStroke()?.clone() || new Stroke();
          stroke.setColor('#ff0000');
          stroke.setWidth(3);
          clone.setStroke(stroke);
          return clone;
        }
        return this.defaultStyle;
      }
    });
    
    this.selectInteraction.on('select', (event: SelectEvent) => {
      const selectedFeatures = event.selected;
      if (selectedFeatures.length > 0) {
        this.emit('featureSelected', selectedFeatures);
      } else {
        this.emit('featureDeselected');
      }
    });
    
    this.map.addInteraction(this.selectInteraction);
  }

  /**
   * 开始绘制
   * @param type 绘制类型
   * @param options 绘制选项
   */
  startDraw(type: DrawType, options?: any): void {
    this.stopCurrentMode();
    this.drawType = type;
    
    // 创建绘制交互
    const drawOptions: any = {
      source: this.source,
      type: type as any,
      style: (feature: any) => {
        // 绘制中的样式
        const geometry = feature.getGeometry();
        const styles: Style[] = [];
        
        // 基础样式
        styles.push(new Style({
          fill: new Fill({ color: 'rgba(255, 165, 0, 0.2)' }),
          stroke: new Stroke({ color: '#ff8c00', width: 2 }),
          image: new Circle({ radius: 6, fill: new Fill({ color: '#ff8c00' }) })
        }));
        
        // 如果是矩形类型，使用特殊样式
        if (type === DrawType.RECTANGLE && geometry) {
          // 简化处理，不再进行transform
          styles[0].setGeometry(geometry.clone());
        }
        
        return styles;
      },
      ...options
    };
    
    // 对于矩形，使用特殊处理
    if (type === DrawType.RECTANGLE) {
      drawOptions.type = 'Circle';
      drawOptions.geometryFunction = (coordinates: number[][], geometry?: any) => {
            const center = coordinates[0];
            const last = coordinates[1];
            const dx = center[0] - last[0];
            const dy = center[1] - last[1];
            const radius = Math.sqrt(dx * dx + dy * dy);
            
            // 直接创建一个新的CircleGeometry，而不是尝试修改现有geometry
            return new CircleGeometry(center, radius);
          };
      drawOptions.maxPoints = 2;
    }
    
    this.drawInteraction = new Draw(drawOptions);
    
    // 监听绘制开始和结束事件
    this.drawInteraction.on('drawstart', (event: DrawEvent) => {
      this.emit('drawStart', event.feature);
    });
    
    this.drawInteraction.on('drawend', (event: DrawEvent) => {
      const feature = event.feature;
      this.addToHistory('add', feature);
      this.emit('drawEnd', feature);
      
      // 如果不是连续绘制模式，自动停止
      if (!options || !options.continueDrawing) {
        this.stopDraw();
      }
    });
    
    this.map.addInteraction(this.drawInteraction);
    
    // 添加吸附
    if (this.snapping) {
      this.snapInteraction = new Snap({
        source: this.source,
        pixelTolerance: this.snappingDistance
      });
      this.map.addInteraction(this.snapInteraction);
    }
    
    console.log(`Draw mode started: ${type}`);
  }

  /**
   * 停止绘制
   */
  stopDraw(): void {
    if (this.drawInteraction) {
      this.map.removeInteraction(this.drawInteraction);
      this.drawInteraction = null;
    }
    
    if (this.snapInteraction) {
      this.map.removeInteraction(this.snapInteraction);
      this.snapInteraction = null;
    }
    
    this.drawType = null;
    console.log('Draw mode stopped');
  }

  /**
   * 开始编辑要素
   * @param features 要编辑的要素集合，不传则编辑所有选中要素
   */
  startEdit(features?: Collection<Feature>): void {
    this.stopCurrentMode();
    
    const featuresToEdit = features || (this.selectInteraction?.getFeatures() || new Collection());
    
    this.modifyInteraction = new Modify({
      features: featuresToEdit,
      style: (feature: any) => {
        // 编辑时的样式
        return new Style({
          image: new Circle({ radius: 8, fill: new Fill({ color: '#00ff00' }) }),
          stroke: new Stroke({ color: '#00ff00', width: 2 })
        });
      }
    });
    
    this.modifyInteraction.on('modifystart', (event: ModifyEvent) => {
      // 保存修改前的状态
      event.features.forEach(feature => {
        this.addToHistory('modify', feature, feature.getGeometry()?.clone());
      });
      this.emit('modifyStart', event.features);
    });
    
    this.modifyInteraction.on('modifyend', (event: ModifyEvent) => {
      this.emit('modifyEnd', event.features);
    });
    
    this.map.addInteraction(this.modifyInteraction);
    
    // 添加吸附
    if (this.snapping) {
      this.snapInteraction = new Snap({
        source: this.source,
        pixelTolerance: this.snappingDistance
      });
      this.map.addInteraction(this.snapInteraction);
    }
    
    console.log('Edit mode started');
  }

  /**
   * 停止编辑
   */
  stopEdit(): void {
    if (this.modifyInteraction) {
      this.map.removeInteraction(this.modifyInteraction);
      this.modifyInteraction = null;
    }
    
    if (this.snapInteraction) {
      this.map.removeInteraction(this.snapInteraction);
      this.snapInteraction = null;
    }
    
    console.log('Edit mode stopped');
  }

  /**
   * 删除选中的要素
   */
  deleteSelectedFeatures(): void {
    if (!this.selectInteraction) return;
    
    const selectedFeatures = this.selectInteraction.getFeatures();
    selectedFeatures.forEach(feature => {
      this.addToHistory('delete', feature, feature.getGeometry()?.clone());
      this.source.removeFeature(feature);
    });
    
    selectedFeatures.clear();
    this.emit('featuresDeleted');
    console.log('Selected features deleted');
  }

  /**
   * 获取所有要素
   */
  getFeatures(): Feature[] {
    return this.source.getFeatures();
  }

  /**
   * 获取选中的要素
   */
  getSelectedFeatures(): Feature[] {
    if (!this.selectInteraction) return [];
    return this.selectInteraction.getFeatures().getArray();
  }

  /**
   * 清除所有要素
   */
  clearFeatures(): void {
    this.source.clear();
    if (this.selectInteraction) {
      this.selectInteraction.getFeatures().clear();
    }
    this.history = [];
    this.historyIndex = -1;
    this.emit('featuresCleared');
    console.log('All features cleared');
  }

  /**
   * 撤销操作
   */
  undo(): void {
    if (this.historyIndex < 0) return;
    
    const item = this.history[this.historyIndex];
    this.historyIndex--;
    
    switch (item.type) {
      case 'add':
        this.source.removeFeature(item.feature);
        break;
      case 'modify':
        if (item.geometry) {
          item.feature.setGeometry(item.geometry);
        }
        break;
      case 'delete':
        this.source.addFeature(item.feature);
        break;
    }
    
    this.emit('undone', item);
    console.log('Undo performed');
  }

  /**
   * 重做操作
   */
  redo(): void {
    if (this.historyIndex >= this.history.length - 1) return;
    
    this.historyIndex++;
    const item = this.history[this.historyIndex];
    
    switch (item.type) {
      case 'add':
        this.source.addFeature(item.feature);
        break;
      case 'modify':
        // 重做修改需要重新应用修改后的几何
        // 这里简化处理，实际可能需要存储修改后的几何
        break;
      case 'delete':
        this.source.removeFeature(item.feature);
        break;
    }
    
    this.emit('redone', item);
    console.log('Redo performed');
  }

  /**
   * 保存编辑结果为GeoJSON
   */
  saveEdits(): string {
    const format = new GeoJSON();
    const geoJSON = format.writeFeatures(this.source.getFeatures());
    this.emit('saved', geoJSON);
    console.log('Edits saved');
    return geoJSON;
  }

  /**
   * 停止当前所有交互模式
   */
  private stopCurrentMode(): void {
    this.stopDraw();
    this.stopEdit();
  }

  /**
   * 添加到历史记录
   */
  private addToHistory(type: 'add' | 'modify' | 'delete', feature: Feature, geometry?: any): void {
    // 清除历史记录中当前位置之后的所有项
    this.history = this.history.slice(0, this.historyIndex + 1);
    
    // 添加新的历史记录项
    this.history.push({ type, feature, geometry });
    this.historyIndex = this.history.length - 1;
    
    // 限制历史记录长度
    const MAX_HISTORY = 50;
    if (this.history.length > MAX_HISTORY) {
      this.history.shift();
      this.historyIndex--;
    }
  }

  /**
   * 添加事件监听
   */
  on(event: string, handler: Function): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)?.push(handler);
  }

  /**
   * 移除事件监听
   */
  off(event: string, handler?: Function): void {
    if (!this.listeners.has(event)) return;
    
    if (handler) {
      const handlers = this.listeners.get(event);
      if (handlers) {
        const index = handlers.indexOf(handler);
        if (index > -1) {
          handlers.splice(index, 1);
        }
      }
    } else {
      this.listeners.delete(event);
    }
  }

  /**
   * 触发事件
   */
  private emit(event: string, ...args: any[]): void {
    const handlers = this.listeners.get(event);
    if (handlers) {
      handlers.forEach(handler => {
        try {
          handler(...args);
        } catch (error) {
          console.error('Error in event handler:', error);
        }
      });
    }
  }

  /**
   * 销毁编辑器
   */
  destroy(): void {
    this.stopCurrentMode();
    
    if (this.selectInteraction) {
      this.map.removeInteraction(this.selectInteraction);
      this.selectInteraction = null;
    }
    
    // 移除图层（如果是编辑器创建的）
    const layers = this.map.getLayers().getArray();
    if (layers.includes(this.layer)) {
      this.map.removeLayer(this.layer);
    }
    
    this.listeners.clear();
    this.history = [];
    console.log('Editor destroyed');
  }
}

/**
   * 标注管理器类，提供高级标注功能
   */
export class LabelManager {
  private map: OlMap;
  private labelLayer: VectorLayer<any>;
  private labelSource: VectorSource<any>;
  
  constructor(map: OlMap) {
    this.map = map;
    this.labelSource = new VectorSource<any>();
    this.labelLayer = new VectorLayer({
      source: this.labelSource,
      style: (feature) => this.createLabelStyle(feature as Feature<Geometry>)
    });
    this.map.addLayer(this.labelLayer);
  }
  
  /**
   * 创建标注样式
   */
  private createLabelStyle(feature: Feature<Geometry>): Style {
    const properties = feature.getProperties();
    const labelStyle = properties.labelStyle || {};
    
    return new Style({
      text: new Text({
        text: labelStyle.text || properties.name || '',
        font: labelStyle.font || '12px Calibri, sans-serif',
        fill: new Fill({ color: labelStyle.color || '#000000' }),
        stroke: new Stroke({ 
          color: labelStyle.strokeColor || '#ffffff', 
          width: labelStyle.strokeWidth || 2 
        }),
        offsetX: labelStyle.offsetX || 0,
        offsetY: labelStyle.offsetY || -15,
        rotation: labelStyle.rotation || 0,
        scale: labelStyle.scale || 1
      }),
      // 可选的图标样式
      image: properties.icon ? new Circle({
        radius: properties.icon.radius || 5,
        fill: new Fill({ color: properties.icon.color || '#ffcc33' })
      }) : undefined
    });
  }
  
  /**
   * 添加标注
   */
  addLabel(lon: number, lat: number, properties: any): Feature {
    const feature = new Feature({
      geometry: new Point([lon, lat]),
      ...properties
    });
    this.labelSource.addFeature(feature);
    return feature;
  }
  
  /**
   * 批量添加标注
   */
  addLabels(labels: Array<{lon: number; lat: number; properties: any}>): Feature[] {
    const features = labels.map(label => {
      return new Feature({
        geometry: new Point([label.lon, label.lat]),
        ...label.properties
      });
    });
    this.labelSource.addFeatures(features);
    return features;
  }
  
  /**
   * 更新标注
   */
  updateLabel(feature: Feature, properties: any): void {
    Object.entries(properties).forEach(([key, value]) => {
      feature.set(key, value);
    });
  }
  
  /**
   * 移除标注
   */
  removeLabel(feature: Feature): void {
    this.labelSource.removeFeature(feature);
  }
  
  /**
   * 清除所有标注
   */
  clearLabels(): void {
    this.labelSource.clear();
  }
  
  /**
   * 设置动态标签样式
   */
  setDynamicStyle(styleFunction: (feature: any) => any): void {
    this.labelLayer.setStyle((feature) => {
      const dynamicStyle = styleFunction(feature);
      const tempFeature = new Feature(feature.getGeometry ? feature.getGeometry() : undefined);
      const properties = feature.getProperties ? feature.getProperties() : {};
      tempFeature.setProperties({ ...properties, labelStyle: dynamicStyle });
      return this.createLabelStyle(tempFeature);
    });
  }
  
  /**
   * 销毁标注管理器
   */
  destroy(): void {
    this.map.removeLayer(this.labelLayer);
    this.labelSource.clear();
  }
}


